package com.zzh.compilation.syntax;

import com.zzh.compilation.model.Token;
import com.zzh.compilation.lexical.LexicalAnalyzer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.zzh.compilation.lexical.LexicalAnalyzer.valueTokenMap;

public class SyntaxAnalyzer {
    private static List<Token> tokens;
    private static int position = 0;
    private static StringBuilder errorMessage = new StringBuilder();
    private static boolean hasError = false;
    private static boolean hasErrorEnd = false;

    public static void analyze(List<Token> inputTokens) {
        tokens = inputTokens;
        if (program()) {
            System.out.println("success: syntax analyze");
        } else {
            System.out.println("error: syntax analyze - " + errorMessage.toString());
        }
    }

    private static boolean program() {
        if (matchTokenType(1)) {
            if (!statementList()) {
                recordError("Invalid statement list");
            }
            if (matchTokenType(6)) { // end
                if (!matchTokenType(28)) {
                    recordError("Missing end symbol '#'");
                }
            } else {
                recordError("Missing 'end' keyword");
//                errorMessage.append("At the end of input: ").append("Missing 'end' keyword").append('\n');
//                hasErrorEnd = true;// 缺少end关键字，后续的语句不再进行语法分析
            }
        } else {
            recordError("Missing 'begin' keyword at the start");
        }
        return !hasError && !hasErrorEnd;
    }

    private static boolean statementList() {
        if (!statement()) {
            recordError("Invalid statement");
            return false;
        }
        while (matchTokenType(25)) {// ;
            if (!statement()) {
                recordError("Invalid statement after ';'");
                return false;
            }
        }
        return true;
    }

    private static boolean statement() {
        return assignmentStatement();
    }

    private static boolean assignmentStatement() {
        if (matchTokenType(10)) {
            if (matchTokenType(18)) {// :=
                return expression();
            }
            recordError("Missing ':=' after variable name");
            return false;
        }
        // 每次到end之后都会来到这一步！
        if ("end".equals(tokens.get(position).getValue())){// 避免每次到这里检查end就爆错
            return true;
        }
        recordError("Missing variable name for assignment statement");
        return false;
    }

    private static boolean expression() { // := 后面的表达式
        if (!term()) {
            recordError("Expected term in expression");
            return false;
        }
        while (matchTokenType(30) || matchTokenType(31)) {// + -
            if (!term()) {
                recordError("Invalid term after '+' or '-'");
                return false;
            }
        }
        return true;
    }

    private static boolean term() {
        if (!factor()) {
            recordError("Expected factor in term");
            return false;
        }
        while (matchTokenType(32) || matchTokenType(33)) { // * /
            if (!factor()) {
                recordError("Invalid factor after '*' or '/'");
                return false;
            }
        }
        return true;
    }

    private static boolean factor() {// 因子
        if (matchTokenType(10) || matchTokenType(0)) {
            return true;
        } else if (matchTokenType(34)) { // (
            if (!expression()) {
                recordError("Invalid expression inside parentheses");
                return false;
            }
            // 再继续判断是否匹配右括号
            if (!matchTokenType(35)) {
                recordError("Missing closing parenthesis ')'");
                return false;
            }
            return true;
        }
        recordError("Expected variable, number or '(' for factor");
        return false;
    }

    // 根据token存放的类型判断是否匹配
    private static boolean matchTokenType(int expectedType) {
        if (position < tokens.size() && tokens.get(position).getType() == expectedType) {
            position++;
            return true;
        }
        return false;
    }

    private static void recordError(String message) {
        if (!hasError && position < tokens.size()) {
            Token currentToken = tokens.get(position);
            errorMessage.append("Line ").append(currentToken.getLineNumber()).append(": ").append(message).append('\n');
            hasError = true;
        }
    }
}